/*
XPTracker - Alternative Agile Tracking Tool
Copyright (C) 2006-2009  Stephen Starkey

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
*/
package org.xptracker.port;

import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Module;
import com.google.inject.TypeLiteral;
import org.xptracker.domain.*;
import org.xptracker.persistence.PersistenceListener;
import org.xptracker.persistence.PersistenceManager;
import org.xptracker.test.IntegrationTest;

import java.io.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;

public class CsvImporterExporterTest extends IntegrationTest {
  private File testFile;
  private OutputStream outputStream;
  private InputStream inputStream;
  private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");

  @Inject
  private CsvExporter csvExporter;

  @Inject
  private CsvImporter cvsImporter;


  protected void beforeInjection(List<Module> modules, List<PersistenceListener> listeners) throws Exception {
    testFile = File.createTempFile("test", ".csv");
    outputStream = new FileOutputStream(testFile);

    modules.add(new AbstractModule() {
      protected void configure() {
        bind(new TypeLiteral<TypeFactory<Story>>() {}).toInstance(new TypeFactory<Story>(PortableFields.makeStoryFields()));
        bind(new TypeLiteral<TypeFactory<User>>() {}).toInstance(new TypeFactory<User>(PortableFields.makeUserFields()));
      }});
  }

  protected void subTeardown() throws IOException {
    if (outputStream != null)
      outputStream.close();
    if (inputStream != null)
      inputStream.close();
    testFile.delete();
  }

  public void testImportExportStories() throws Exception {
    final Story story = new Story();
    final String summary1 = "Test Summary 1";
    story.setSummary(summary1);
    story.setDescription("This is a realy long description. it contains commas ',' and quotes '\"'.");
    story.setCompletedDate(new Date());
    story.setDueDate(formatter.parse("2006-01-01"));
    story.setLastModified(formatter.parse("2006-01-09"));
    story.setSize(Size.large);
    story.setEstimate(2.0);
    final StoryCategory category1 = new StoryCategory("1");
    final StoryCategory category2 = new StoryCategory("2");
    story.setCategories(Arrays.asList(category1, category2));
    story.setSeverity(Severity.cold);
    final Story story2 = new Story();
    story.setState(State.developed);
    final String summary2 = "Test summary 2";
    story2.setSummary(summary2);
    story2.setDescription("\"Description 2,\"");

    mgr.inTransaction(new PersistenceManager.UpdateHandler<Object>() {
      public Object doUpdate(PersistenceManager.UpdateReceiver receiver) {
        receiver.insert(category1);
        receiver.insert(category2);
        receiver.insert(story);
        receiver.insert(story2);
        return null;
      }
    });

    List<Story> stories = Arrays.asList(story, story2);
    csvExporter.exportStories(outputStream, stories);
    outputStream.close();

    inputStream = new FileInputStream(testFile);
    Collection<Story> results = cvsImporter.importStories(inputStream, new PersistenceManager.UpdateReceiver() {
      public void insert(Object o) {}
      public void update(Object o) {}
      public void remove(Object o) {}
    });
    inputStream.close();

    assertNotNull(results);
    assertEquals(2, results.size());
    for (Story result : results) {
      final String summary = result.getSummary();
      if (summary1.equals(summary)) {
        areEqual(story, result);
        assertEquals(story.getSeverity(), result.getSeverity());
        assertEquals(story.getSize(), result.getSize());
        assertEquals(story.getEstimate(), result.getEstimate());
        assertEquals(story.getState(), result.getState());

        final List<StoryCategory> expectedCats = result.getCategories();
        assertEquals(2, expectedCats.size());
        assertTrue(expectedCats.contains(category1));
        assertTrue(expectedCats.contains(category2));

      } else if (summary2.equals(summary)) {
        areEqual(story2, result);
      } else {
        fail("Got a story with a bad summary: " + summary);
      }
    }
  }

  public void testUserExport() throws Exception {
    final User user = new User("frodo");
    user.setFullName("Frodo Baggins");
    user.setEmail("frodobaggins@nodomain.com");
    user.setPhoneNumber("123 456 7890");
    mgr.inTransaction(new PersistenceManager.UpdateHandler<Object>() {
      public Object doUpdate(PersistenceManager.UpdateReceiver receiver) {
        receiver.insert(user);
        return null;
      }
    });

    csvExporter.exportUsers(outputStream, Arrays.asList(user));

    inputStream = new FileInputStream(testFile);
    Collection<User> users = cvsImporter.importUsers(inputStream);
    assertNotNull(users);
    assertEquals(1, users.size());
    User result = users.iterator().next();
    assertEquals(user.getUsername(), result.getUsername());
    assertEquals(user.getFullName(), result.getFullName());
    assertEquals(user.getEmail(), result.getEmail());
    assertEquals(user.getPhoneNumber(), result.getPhoneNumber());
  }


  private void areEqual(Story story, Story result) {
    DateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    assertEquals(story.getDescription(), result.getDescription());
    if (story.getCompletedDate() != null) {
      assertEquals(format.format(story.getCompletedDate()), format.format(result.getCompletedDate()));
    }
    if (story.getDueDate() != null) {
      assertEquals(format.format(story.getDueDate()), format.format(result.getDueDate()));
    }
    assertEquals(format.format(story.getLastModified()), format.format(result.getLastModified()));
  }
}
